package com.bmt.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * 日期和时间处理工具类
 * 
 * @author mickyfeng on 14-1-10.
 * 
 */
public class DateUtils {

    private static final String ISO = "yyyy-MM-dd HH:mm:ss";
    private static final String ISO_DATE = "yyyy-MM-dd";
    private static final String ISO_TIME = "HH:mm:ss";
    private static final SimpleDateFormat SDF_ISO = new SimpleDateFormat(ISO);
    private static final SimpleDateFormat SDF_ISO_DATE = new SimpleDateFormat(ISO_DATE);
    private static final SimpleDateFormat SDF_ISO_TIME = new SimpleDateFormat(ISO_TIME);

    private DateUtils() {

    }

    /**
     * 根据给定的格式创建一个格式化器.
     * 
     * @see java.text.SimpleDateFormat
     * 
     * @param fmt 日期/时间格式
     * @return 格式化器
     */
    public static SimpleDateFormat createDateFormater(String fmt) {
        return new SimpleDateFormat(fmt);
    }

    /**
     * 将ISO格式的DateTime字符串按转换为Date对象.
     * 
     * @param dateTime 要转换的DateTime值
     * @return 返回转换后的Date对象,如果参数time为null则返回null.
     * 
     * @throws IllegalArgumentException 如果给定的DateTime值不符合ISO格式,则抛出此异常.
     */
    public static Date convert(String dateTime) {
        if (dateTime == null)
            return null;
        try {
            return SDF_ISO.parse(dateTime);
        } catch (ParseException e) {
            throw new IllegalArgumentException("The date's format is invalid,date convert fail");
        }
    }

    /**
     * 将DateTime字符串按指定的格式转换成Date对象.
     * 
     * @param dateTime 要转换的DateTime值
     * @param fmt 要转换的DateTime值的格式
     * @return 返回转换后的Date对象,如果任何参数为null则返回null.
     * 
     * @throws IllegalArgumentException 如果给出的DateTime值与格式不匹配,则抛出此异常.
     */
    public static Date convert(String dateTime, String fmt) {
        if (dateTime == null || fmt == null)
            return null;
        try {
            return createDateFormater(fmt).parse(dateTime);
        } catch (ParseException e) {
            throw new IllegalArgumentException("The date's format is invalid,date convert fail");
        }
    }

    /**
     * 将一个Date对象转换为ISO格式的DateTime字符串形式.
     * 
     * @param date 要转换的Date
     * @return 如果要转换的Date为null则返回空字符串,否则返回转换后的结果.
     */
    public static String convert(Date date) {
        if (date == null)
            return "";
        return SDF_ISO.format(date);
    }

    /**
     * 将一个Date对象转换为指定格式的字符串形式.
     * 
     * @param date 要转换的Date
     * @aram fmt 格式
     * @return 如果要转换的Date为null则返回空字符串,否则返回转换后的结果.
     */
    public static String convert(Date date, String fmt) {
        if (date == null)
            return "";
        return createDateFormater(fmt).format(date);
    }

    /**
     * 将一个ISO日期格式的字符串转换为Date对象.只转换日期部分.
     * 
     * @param date 要转换的Date值
     * @return 如果要转换的Date为null则返回空字符串,否则返回转换后的结果.
     * 
     * @throws IllegalArgumentException 如果给定的DateTime值不符合ISO格式,则抛出此异常.
     */
    public static Date convertDate(String date) {
        if (date == null)
            return null;
        try {
            return SDF_ISO_DATE.parse(date);
        } catch (ParseException e) {
            throw new IllegalArgumentException("The date's format is invalid,date convert fail");
        }
    }

    /**
     * 将一个Date对象转换为ISO日期格式的字符串.只转换日期.
     * 
     * @param date 要转换的Date
     * @return 如果要转换的Date为null则返回空字符串,否则返回转换后的结果.
     */
    public static String convertDate(Date date) {
        if (date == null)
            return "";
        return SDF_ISO_DATE.format(date);
    }

    /**
     * 将一个Date对象转换为ISO日期格式的字符串.只转换时间.
     * 
     * @param date 要转换的time
     * @return 如果要转换的Date为null则返回空字符串,否则返回转换后的结果.
     */
    public static String convertTime(Date date) {
        if (date == null)
            return "";
        return SDF_ISO_TIME.format(date);
    }

    /**
     * 抽取日期部分.
     */
    public static Date extractDate(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 返回当前日期和时间,ISO格式.
     */
    public static String current() {
        return convert(new Date());
    }

    /**
     * 返回当天(只有日期),ISO格式.
     */
    public static String currentDate() {
        return convertDate(new Date());
    }

    /**
     * 返回当前日期和时间.
     */
    public static Date now() {
        return new Date();
    }

    /**
     * 返回当前日期.
     */
    public static Date today() {
        Date date = new Date();
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        date = cal.getTime();
        return date;
    }

    private static final long MILLISECOND_FOR_SECOND = 1000;
    private static final long MILLISECOND_FOR_MINUTE = 1000 * 60;
    private static final long MILLISECOND_FOR_HOUR = 1000 * 60 * 60;
    private static final long MILLISECOND_FOR_DAY = 1000 * 60 * 60 * 24;
    private static long[] MILLISECONDS;

    static {
        MILLISECONDS = new long[17];
        MILLISECONDS[Calendar.DATE] = MILLISECOND_FOR_DAY;
        MILLISECONDS[Calendar.HOUR] = MILLISECOND_FOR_HOUR;
        MILLISECONDS[Calendar.HOUR_OF_DAY] = MILLISECOND_FOR_HOUR;
        MILLISECONDS[Calendar.MINUTE] = MILLISECOND_FOR_MINUTE;
        MILLISECONDS[Calendar.SECOND] = MILLISECOND_FOR_SECOND;
        MILLISECONDS[Calendar.MILLISECOND] = 1;
    }

    /**
     * 计算两个日期之间的天数.
     * @param startDate
     * @param endDate
     * @return 如果结束日期早于开始之前则返回-1;
     */
    public static int diffDate(Date startDate, Date endDate) {
        if (startDate == null || endDate == null)
            throw new IllegalArgumentException("The startDate and endDate can't be null!");

        return diff(endDate, startDate, Calendar.DATE).intValue();
    }

    public static int diffHour(Date startDate, Date endDate) {
        if (startDate == null || endDate == null)
            throw new IllegalArgumentException("The startDate and endDate can't be null!");

        return diff(endDate, startDate, Calendar.HOUR).intValue();
    }

    public static int diffMinute(Date startDate, Date endDate) {
        if (startDate == null || endDate == null)
            throw new IllegalArgumentException("The startDate and endDate can't be null!");

        return diff(endDate, startDate, Calendar.MINUTE).intValue();
    }

    public static int diffSecond(Date startDate, Date endDate) {
        if (startDate == null || endDate == null)
            throw new IllegalArgumentException("The startDate and endDate can't be null!");

        return diff(endDate, startDate, Calendar.SECOND).intValue();
    }

    /**
     * 计算两个日期之间的相差. startDate大于endDate返回值为正数,如: diffMonth("2010-01-02", "2009-01-01") --相差12个月 diffMonth("2009-01-01",
     * "2010-01-02") --相差-12个月
     */
    public static int diffMonth(Date startDate, Date endDate) {
        if (startDate == null || endDate == null)
            throw new IllegalArgumentException("The startDate and endDate can't be null!");

        Calendar cal1 = GregorianCalendar.getInstance();
        cal1.setTime(startDate);

        Calendar cal2 = GregorianCalendar.getInstance();
        cal2.setTime(endDate);

        int sy = cal1.get(Calendar.YEAR);
        int ey = cal2.get(Calendar.YEAR);
        int sm = cal1.get(Calendar.MONTH);
        int em = cal2.get(Calendar.MONTH);
        return (sy - ey) * 12 + sm - em;
    }

    /**
     * 计算两个时间之差,只相对于给定的类型.<br/> eq. <br/> diff("2009-01-02 00:00:01", "2009-01-01 23:59:59", Calendar.DATE) = 1 天 <br/>
     * diff("2009-01-02 00:00:01", "2009-01-01 23:59:59", Calendar.HOUR) = 1小时 <br/> diff("2009-01-02 00:00:01",
     * "2009-01-01 23:59:59", Calendar.MINITE) = 1分钟 <br/> diff("2009-01-02 00:00:01", "2009-01-01 23:59:59",
     * Calendar.SECOND) = 2秒 <br/> diff("2009-01-02 00:00:01", "2009-01-01 23:59:59", Calendar.MILLISECOND) = 2000毫秒
     * <br/>
     * @param date1 被减数
     * @param date2 减数
     * @param type
     *        计算类型.Calendar.DATE计算相差几日;Calendar.HOUR计算相差几小时;Calendar.MINUTE计算相差几分钟;Calendar.SECOND计算相差几秒;Calendar.MILLISECOND计算相差几毫秒;
     */
    public static Long diff(Date date1, Date date2, int type) {
        if (date1 == null || date2 == null)
            throw new IllegalArgumentException("The argument can't be null!");

        Date d1 = new Date(date1.getTime());
        Calendar cal1 = GregorianCalendar.getInstance();
        cal1.setTime(d1);

        Date d2 = new Date(date2.getTime());
        Calendar cal2 = GregorianCalendar.getInstance();
        cal2.setTime(d2);

        switch (type) {
        case Calendar.DATE:
            cal1.set(Calendar.HOUR_OF_DAY, 0);
            cal2.set(Calendar.HOUR_OF_DAY, 0);
        case Calendar.HOUR:
            cal1.set(Calendar.MINUTE, 0);
            cal2.set(Calendar.MINUTE, 0);
        case Calendar.MINUTE:
            cal1.set(Calendar.SECOND, 0);
            cal2.set(Calendar.SECOND, 0);
        case Calendar.SECOND:
            cal1.set(Calendar.MILLISECOND, 0);
            cal2.set(Calendar.MILLISECOND, 0);
        case Calendar.MILLISECOND:
            break;
        default:
            throw new IllegalArgumentException("The type illegal!");
        }
        d1 = cal1.getTime();
        d2 = cal2.getTime();

        Long diff = (d1.getTime() - d2.getTime()) / MILLISECONDS[type];
        return diff;
    }

    public static Date max(Date d1, Date d2) {
        return d1.compareTo(d2) > 0 ? d1 : d2;
    }

    public static Date min(Date d1, Date d2) {
        return d1.compareTo(d2) < 0 ? d1 : d2;
    }

    /**
     * 得到年份
     * @param date
     * @return
     */
    public static int getYear(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.YEAR);
    }

    /**
     * 得到月份(显示月份),如1月为返回1;
     * @param date
     * @return
     */
    public static int getMonth(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * 得到月份(系统使用月份),如1月为返回0;
     * @param date
     * @return
     */
    public static int getMonth_sys(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.MONTH);
    }

    /**
     * 得到月份(字符月份),如1月为返回01;
     * @param date
     * @return
     */
    public static String getMonth_str(Date date) {
        int month = getMonth(date);
        if (month < 10) {
            return "0" + String.valueOf(month);
        }
        return String.valueOf(month);
    }

    /**
     * 在此月份第多少天.就也是几号了.
     * @param date
     * @return
     */
    public static int getDayOfMonth(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 星期几
     * @param date
     * @return
     */
    public static int getDayOfWeek(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.get(Calendar.DAY_OF_WEEK);
    }

    public static Date add(Date date, int field, int amount) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.add(field, amount);
        return cal.getTime();
    }

    /**
     * 添加天数
     * @param date
     * @param amount
     * @return
     */
    public static Date addDay(Date date, int amount) {
        return add(date, Calendar.DAY_OF_YEAR, amount);
    }

    /**
     * 添加月数
     * @param date
     * @param amount
     * @return
     */
    public static Date addMonth(Date date, int amount) {
        return add(date, Calendar.MONTH, amount);
    }

    /**
     * 添加年数
     * @param date
     * @param amount
     * @return
     */
    public static Date addYear(Date date, int amount) {
        return add(date, Calendar.YEAR, amount);
    }

    /**
     * 得到此日期的一年的第一天
     * @param date:日期
     * @return
     */
    public static Date getFirstDateInYear(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_YEAR, 1);
        return cal.getTime();
    }

    /**
     * 得到此年的第一天
     * @param year:年份
     * @return
     */
    public static Date getFirstDateInYear(int year) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.DAY_OF_YEAR, 1);
        return cal.getTime();
    }

    /**
     * 得到这一年的最后一天
     * @param year
     * @return
     */
    public static Date getLastDateInYear(int year) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }

    /**
     * 得到这一年的天数
     * @param year
     * @return
     */
    public static int getDaysByYear(Integer year) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, Calendar.DECEMBER);
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.get(Calendar.DAY_OF_YEAR);

    }

    /**
     * 检验是否日期格式
     * @param date
     * @return
     */
    public static boolean isDateFormat(String date) {
        try {// 尝试转换
            convertDate(date);
            return true;
        } catch (Exception e) {
            return false;// 转换出错;
        }
    }

    /**
     * 得到这一月的天数
     * @param date
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 得到这一月的天数
     * @param year
     * @param month 为正常月份.如果是1月,请传1.
     * @return
     */
    public static int getDaysOfMonth(Integer year, Integer month) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Integer.valueOf(year), getMonth_sys(Integer.valueOf(month)), 1);
        return cal.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 得到此个月的第一天
     * @param date
     * @return
     */
    public static Date getFirstDateInMonth(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DATE, 01);
        return cal.getTime();
    }

    /**
     * 得到此个月的最后一天
     * @param date
     * @return
     */
    public static Date getLastDateInMonth(Date date) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }

    /**
     * 得到月份的第一天.
     * @param year
     * @param month_sys :为系统中的使用日期:如1月为0;
     * @return
     */
    public static Date getFirstDateInMonth(int year, int month_sys) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month_sys);
        cal.set(Calendar.DATE, 01);
        return cal.getTime();
    }

    /**
     * 得到月份的最后一天.
     * @param year
     * @param month_sys :为系统中的使用日期:如1月为0;
     * @return
     */
    public static Date getLastDateInMonth(int year, int month_sys) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month_sys);
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return cal.getTime();
    }

    /**
     * 昨天
     * @return
     */
    public static Date yesterday() {
        Date date = new Date();
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.DATE, -1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        date = cal.getTime();
        return date;
    }

    /**
     * 前一个月的第一天.
     * @return
     */
    public static Date getFirstDateBeforeMonth() {
        Date date = new Date();
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        date = cal.getTime();
        return date;
    }

    /**
     * 前一个月的最后一天
     * @return
     */
    public static Date getLastDateBeforeMonth() {
        Date date = new Date();
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MONTH, -1);
        cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        date = cal.getTime();
        return date;
    }

    public static int getMonth_sys(int month) {
        // January February March April May June July August September October November December
        switch (month) {
        case 1:
            return Calendar.JANUARY;
        case 2:
            return Calendar.FEBRUARY;
        case 3:
            return Calendar.MARCH;
        case 4:
            return Calendar.APRIL;
        case 5:
            return Calendar.MAY;
        case 6:
            return Calendar.JUNE;
        case 7:
            return Calendar.JULY;
        case 8:
            return Calendar.AUGUST;
        case 9:
            return Calendar.SEPTEMBER;
        case 10:
            return Calendar.OCTOBER;
        case 11:
            return Calendar.NOVEMBER;
        case 12:
            return Calendar.DECEMBER;
        default:
            break;
        }
        return -1;
    }

    public static String getWeekLast(String strDate) {
        return getWeekLast(convertDate(strDate));
    }

    public static String getWeekLast(Date date) {
        int w = getDayOfWeek(date);
        switch (w) {
        case Calendar.SUNDAY:
            return "日";
        case Calendar.MONDAY:
            return "一";
        case Calendar.TUESDAY:
            return "二";
        case Calendar.WEDNESDAY:
            return "三";
        case Calendar.THURSDAY:
            return "四";
        case Calendar.FRIDAY:
            return "五";
        case Calendar.SATURDAY:
            return "六";
        }
        return "";// 如果还返回空,那就是出问题了.
    }

    public static Date setTime(Date date, int hour, int minute, int second) {
        Calendar cal = GregorianCalendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, hour);
        cal.set(Calendar.MINUTE, minute);
        cal.set(Calendar.SECOND, second);
        cal.set(Calendar.MILLISECOND, 0);
        date = cal.getTime();
        return date;
    }

}
